package com.dyna.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dyna.constants.RedisKeyConstant;
import com.dyna.core.exception.CustomException;
import com.dyna.core.utils.ObjectUtil;
import com.dyna.core.utils.PageUtil;
import com.dyna.core.utils.SecurityUtil;
import com.dyna.domain.dto.LoginUser;
import com.dyna.domain.entity.Items;
import com.dyna.domain.event.WarehouseEvent;
import com.dyna.domain.form.item.ItemsForm;
import com.dyna.domain.req.ItemFlashPurchaseReq;
import com.dyna.domain.req.ItemPageReq;
import com.dyna.domain.req.PageParam;
import com.dyna.domain.resp.PageResult;
import com.dyna.domain.resp.item.ItemPageResp;
import com.dyna.enums.SkuStatusEnum;
import com.dyna.lua.LuaScript;
import com.dyna.mapper.ItemsMapper;
import com.dyna.service.ItemsService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Optional;

/**
 * @description items
 * @author zcw
 * @date 2025-02-27
 */
@Slf4j
@Service
public class ItemsServiceImpl extends ServiceImpl<ItemsMapper, Items> implements ItemsService{

	private final ItemsMapper itemsMapper;
	private final StringRedisTemplate stringRedisTemplate;
	private final ApplicationEventPublisher applicationEventPublisher;

	@Autowired
	public ItemsServiceImpl(ItemsMapper itemsMapper,
							StringRedisTemplate stringRedisTemplate,
							ApplicationEventPublisher applicationEventPublisher
	) {
		this.itemsMapper = itemsMapper;
		this.stringRedisTemplate = stringRedisTemplate;
		this.applicationEventPublisher = applicationEventPublisher;
	}

	@Override
	public PageResult<ItemPageResp> pageList(ItemPageReq req) {
		PageParam pageParam = PageUtil.getPageParam();
		Page<ItemPageResp> page = PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()).doSelectPage(() -> itemsMapper.queryPageList(req));
		return new PageResult<>(page.getResult(), page.getTotal());
	}

	@Override
	public Boolean add(ItemsForm form) {
		LoginUser userInfo = SecurityUtil.getUserInfo();
		Optional.ofNullable(userInfo).orElseThrow(()-> new CustomException("获取登录用户信息失败"));
		Items items = BeanUtil.copyProperties(form, Items.class);
		items.setItemId(IdUtil.getSnowflakeNextId());
		items.setStatus(SkuStatusEnum.PRE_SOLD.getStatus());
		this.save(items);
		return Boolean.TRUE;
	}

	@Override
	public Boolean del(Long itemId) {
		return baseMapper.del(itemId);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Boolean purchase(ItemFlashPurchaseReq req) {
		Long userId = SecurityUtil.getUserId();
		String stockKey = RedisKeyConstant.ITEM_LIST_KEY + req.getItemId();
		// 执行脚本，当购买数量小于库存数量，返回-1.当大于等于库存数量增量自减库存
		DefaultRedisScript<Long> script = new DefaultRedisScript<>(LuaScript.DECR_LUA_SCRIPT, Long.class);
		Long decrement = stringRedisTemplate.execute(script, Collections.singletonList(stockKey), String.valueOf(req.getCount()));
		// 从redis中扣减库存
		log.info("从redis扣减库存结果:::{}", decrement);
		// 库存不足
		if (ObjectUtil.isNotNull(decrement) && decrement < 0L) {
			throw new CustomException("库存不足，购买失败");
		}
		// 异步操作去扣减数据库库存和保存到寄存柜
		applicationEventPublisher.publishEvent(new WarehouseEvent(this, userId, req.getCount(), req.getItemId()));
		return Boolean.TRUE;
	}

}